package cn.kmsoft.gistool.util;

import cn.kmsoft.common.utils.StringUtil;
import cn.kmsoft.stgeometry.landm.StgeoFeature;
import cn.kmsoft.stgeometry.util.JTSGeometryWKTUtil;
import cn.kmsoft.wololo.object.GeoJson;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.index.quadtree.Quadtree;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import com.vividsolutions.jts.io.WKTWriter;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.io.File;
import java.io.Serializable;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.*;


/**
 * 基于JTS实现的空间拓扑操作类，包括了图形叠加、图形擦除、联合等操作
 *
 * @author wangq
 *
 */
public class JTSGeometryOperations {
    private static GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
    public static boolean bFirstAttributeSaved = true;
    public static boolean bSecondAttributeSaved = true;

    /**
     * Intersect 两个面图形（polygon）的相交叠加分析
     *
     * @param wktPolygon1
     * @param wktPolygon2
     *
     * @return Wkt
     * @throws ParseException
     */
    public static String geomOperIntersect(String wktPolygon1, String wktPolygon2) throws ParseException {
        // GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter write = new WKTWriter();
        Polygon polygon1 = (Polygon) reader.read(wktPolygon1);
        Polygon polygon2 = (Polygon) reader.read(wktPolygon2);

        System.out.println("");
        System.out.println("------空间分析，相交叠加-------");
        Geometry intersection = polygon1.intersection(polygon2);
        String intersectWkt = write.write(intersection);
        System.out.println(intersectWkt);

        return intersectWkt;
    }

    /**
     * 两个面图形（polygon）的空间差异分析（对称扣除）
     *
     * @param wktPolygon1
     * @param wktPolygon2
     * @return
     * @throws ParseException
     */
    public static String geomOperSymDifference(String wktPolygon1, String wktPolygon2) throws ParseException {
        String res = "";
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter write = new WKTWriter();
        Polygon polygon1 = (Polygon) reader.read(wktPolygon1);
        Polygon polygon2 = (Polygon) reader.read(wktPolygon2);

        System.out.println("");
        System.out.println("------空间分析，Sym擦出叠加-------");
        if (polygon1.intersects(polygon2)) {
            Geometry symdifference = polygon1.symDifference(polygon2);

            String diffWKT = write.write(symdifference);
            System.out.println(diffWKT);
            res = diffWKT;
        }
        return res;
    }

    /**
     * Union 两个面图形（polygon）的联合叠加分析
     *
     * @param wktPolygon1
     * @param wktPolygon2
     * @return
     * @throws ParseException
     */
    public static String geomOperUnion(String wktPolygon1, String wktPolygon2) throws ParseException {
        // GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter write = new WKTWriter();
        Polygon polygon1 = (Polygon) reader.read(wktPolygon1);
        Polygon polygon2 = (Polygon) reader.read(wktPolygon2);

        System.out.println("");
        System.out.println("------空间分析，联合叠加-------");

        Geometry union = polygon1.union(polygon2);
        String unionWkt = write.write(union);
        System.out.println(unionWkt);

        return unionWkt;

    }

    /**
     * Difference 两个面图形（polygon）擦除叠加分析
     *
     * @param wktPolygon1 待擦除图形的Polygon Wkt格式
     * @param wktPolygon2 擦除范围的Polygon Wkt格式
     *
     * @return 剩余范围的Wkt
     *
     * @throws ParseException
     */
    public static String geomOperDifference(String wktPolygon1, String wktPolygon2) throws ParseException {
        // GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        String res = "";
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter write = new WKTWriter();
        Polygon polygon1 = (Polygon) reader.read(wktPolygon1);
        Polygon polygon2 = (Polygon) reader.read(wktPolygon2);

        System.out.println("");
        System.out.println("------空间分析，擦出叠加-------");
        if (polygon1.intersects(polygon2)) {
            Geometry difference = polygon1.difference(polygon2);

            String diffWKT = write.write(difference);
            // System.out.println(diffWKT);
            res = diffWKT;
        }
        return res;
    }

    public static String geomOperDifferenceEx(String wktMPolygon1, String wktMPolygon2) throws ParseException {
        // GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter write = new WKTWriter();
        MultiPolygon multiPolygon1 = (MultiPolygon) reader.read(wktMPolygon1);
        MultiPolygon multiPolygon2 = (MultiPolygon) reader.read(wktMPolygon2);

        System.out.println("");
        System.out.println("------空间分析，擦出叠加-------");

        Geometry difference = multiPolygon1.difference(multiPolygon2);

        String diffWKT = write.write(difference);
        // System.out.println(diffWKT);

        return diffWKT;
    }

    public static void geoRelJudge(String wktPoint, String wktLine, String wktPolygon, String wktPolygon1)
            throws ParseException {
        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
        WKTReader reader = new WKTReader(geometryFactory);

        Point point = (Point) reader.read(wktPoint);
        LineString line = (LineString) reader.read(wktLine);
        Polygon polygon = (Polygon) reader.read(wktPolygon);
        Polygon polygon1 = (Polygon) reader.read(wktPolygon1);

        System.out.println("-------空间关系判断-------");
        System.out.println(polygon.contains(point));
        System.out.println(polygon.intersects(line));
        System.out.println(polygon.overlaps(polygon1));
    }

    public static void geoRelJudge(GeoJson inGeoJson1, GeoJson inGeoJson2, String encoding) throws ParseException {
        int feaCount1 = inGeoJson1.getFeatures().size();
        int feaCount2 = inGeoJson2.getFeatures().size();
        if (feaCount1 == 0 || feaCount2 == 0) {
            return;
        }

        // 2-GeoJson对象转换为Polygon 图形Wkt
        String geoType = inGeoJson1.getFeatures().get(0).getGeometry().getType();
        System.out.println();
        System.out.println("--->geoType: " + geoType);
        System.out.println("--->1，读取GeoJson图形");

        List<StgeoFeature> stgeoFea1 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson1);// 被擦除的数据
        List<StgeoFeature> stgeoFea2 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson2);// 擦除范围

        System.out.println(String.format("--->被擦除的数据 size : %d ", stgeoFea1.size()));
        // 3-遍历被叠加的图层数据（批而未供），建立空间索引
        System.out.println();
        System.out.println("--->2，建立空间索引");
        Quadtree quadTree = new Quadtree();
        Iterator<StgeoFeature> iterator1 = stgeoFea1.iterator();
        while (iterator1.hasNext()) {
            StgeoFeature feature1 = iterator1.next();
            Geometry geom1 = (Geometry) feature1.getGeometry();
            Envelope itemEnv = geom1.getEnvelopeInternal();

            quadTree.insert(itemEnv, feature1);
        }

        // 通过初步判断，获取哪些图形被擦除数据inGeoJson1与擦除范围inGeoJson2相交
        System.out.println();
        System.out.println("--->3，空间关系判断");
        Set<StgeoFeature> intersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        for (int i = 0; i < stgeoFea2.size(); i++) {
            StgeoFeature stFea2 = stgeoFea2.get(i);
            Geometry geom2 = stFea2.getGeometry();

            // 图形的包络线相交
            List<StgeoFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
            int envelopeIntersectSize = envelopeIntersections.size();
            for (int j = 0; j < envelopeIntersectSize; j++) {
                System.out.println();
                StgeoFeature stFea1 = envelopeIntersections.get(j);
                Map<String, Object> properties = stFea1.getProperties();
                // 1-属性
                int k = 0;
                for (Map.Entry<String, Object> prop : properties.entrySet()) {
                    k++;
                    String name = prop.getKey().toLowerCase();
                    Object val = prop.getValue();
                    String attrVal = val == null ? "" : val.toString();
                    // String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");

                    // System.out.println(String.format("-->%d, prop name: %s, val: %s", k, name,
                    // attrVal));
                }
                System.out.println(
                        String.format("--> prop name: %s, val: %s", "OBJECTID", properties.get("OBJECTID").toString()));

                // 2-几何图形
                Geometry geom1 = stFea1.getGeometry();
                // StgeoFeature重载了hashCode代码。采用空间判断是否相交进行数据类
                if (geom1.intersects(geom2)) {
                    intersectSTGeoFeaSet.add(stFea1);
                }
            }
        }

        System.out.println();
        System.out.println(String.format("--->intersectSTGeoFeaSet size : %d ", intersectSTGeoFeaSet.size()));

        Set<StgeoFeature> nullIntersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        for (int j = 0; j < stgeoFea1.size(); j++) {
            StgeoFeature stFea1 = stgeoFea1.get(j);
            if (!intersectSTGeoFeaSet.contains(stFea1)) {
                nullIntersectSTGeoFeaSet.add(stFea1);
            }
        }
        System.out.println(String.format("--->nullIntersectSTGeoFeaSet size : %d ", nullIntersectSTGeoFeaSet.size()));

    }

    /**
     * 空间相交操作
     *
     * @param inputPath1  shp1物理路径
     * @param inputPath2  shp2物理路径
     * @param outputPath  相交结果的输出物理路径
     * @throws Exception
     */
    public static void spatialIntersect(String inputPath1, String inputPath2, String outputPath) throws Exception {

        try {
            File inputFile1 = new File(inputPath1);
            File inputFile2 = new File(inputPath2);

            ShapefileDataStore shpDataStore1 = new ShapefileDataStore(inputFile1.toURL());
            ShapefileDataStore shpDataStore2 = new ShapefileDataStore(inputFile2.toURL());

            // 属性编码
            Charset charset = Charset.forName("GBK");
            shpDataStore1.setCharset(charset);
            shpDataStore2.setCharset(charset);
            String typeName1 = shpDataStore1.getTypeNames()[0];
            String typeName2 = shpDataStore2.getTypeNames()[0];

            SimpleFeatureSource featureSource1 = shpDataStore1.getFeatureSource(typeName1);
            SimpleFeatureSource featureSource2 = shpDataStore2.getFeatureSource(typeName2);
            SimpleFeatureCollection featureCollection1 = featureSource1.getFeatures();
            SimpleFeatureCollection featureCollection2 = featureSource2.getFeatures();

            SimpleFeatureType sfType = featureSource1.getSchema();
            CoordinateReferenceSystem targetCRS = sfType.getCoordinateReferenceSystem();
            /**
             * mapFields记录的是两个图层的属性名称， 在处理第二个图层的时候，如果已经有了这个名称， 会在字段后面加‘_1’予以区分
             * fields1为图层1的字段 fields2为图层2的字段
             */
            Map<String, Class> mapFields = new HashMap();
            List<Map> fields1 = new ArrayList();
            List<Map> fields2 = new ArrayList();

            SimpleFeatureType featureType1 = featureCollection1.getSchema();
            List<AttributeDescriptor> attrList1 = featureType1.getAttributeDescriptors();
            for (int i = 0; i < attrList1.size(); i++) {
                AttributeDescriptor attr = attrList1.get(i);
                String name = attr.getName().toString();
                Class type = attr.getType().getBinding();
                if (name != "the_geom") {
                    mapFields.put(name, type);

                    Map map = new HashMap();
                    map.put("fieldShp", name);
                    map.put("fieldNew", name);
                    fields1.add(map);
                }
            }
            SimpleFeatureType featureType2 = featureCollection2.getSchema();
            List<AttributeDescriptor> attrList2 = featureType2.getAttributeDescriptors();
            for (int j = 0; j < attrList2.size(); j++) {
                AttributeDescriptor attr = attrList2.get(j);
                String name = attr.getName().toString();
                Class type = attr.getType().getBinding();
                if (name != "the_geom") {
                    String _name = name;
                    if (mapFields.containsKey(name)) {
                        _name = _name + "_1";
                    }
                    mapFields.put(_name, type);

                    Map map = new HashMap();
                    map.put("fieldShp", name);
                    map.put("fieldNew", _name);
                    fields2.add(map);
                }
            }

            // 遍历被叠加的图层数据（建设用地管制区），建立空间索引
            Quadtree quadTree = new Quadtree();
            SimpleFeatureIterator iterator1 = featureCollection1.features();
            while (iterator1.hasNext()) {
                SimpleFeature feature1 = iterator1.next();
                Geometry geom1 = (Geometry) feature1.getDefaultGeometry();
                Envelope itemEnv = geom1.getEnvelopeInternal();

                quadTree.insert(itemEnv, feature1);
            }

            // 创建输出文件
            File outputFile = new File(outputPath);
            Map<String, Serializable> params = new HashMap<String, Serializable>();
            params.put(ShapefileDataStoreFactory.URLP.key, outputFile.toURI().toURL());
            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
            // 定义图形信息和属性信息
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.setCRS(targetCRS);
            tb.setName("shapefile");
            tb.add("the_geom", MultiPolygon.class);
            for (String key : mapFields.keySet()) {
                tb.add(key, mapFields.get(key));
            }
            ds.createSchema(tb.buildFeatureType());
            // 设置编码
            ds.setCharset(charset);
            // 设置Writer
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0],
                    Transaction.AUTO_COMMIT);

            // 记录已经参与过计算的数据
            Map hasDone = new HashMap();
            // 遍历yjjbnt的所有数据，并逐个gzq进行相交叠加
            SimpleFeatureIterator itertor2 = featureCollection2.features();
            while (itertor2.hasNext()) {
                SimpleFeature feature2 = itertor2.next();
                Geometry geom2 = (Geometry) feature2.getDefaultGeometry();
                String id2 = feature2.getID();

                List<SimpleFeature> intersectResults = new ArrayList<SimpleFeature>();
                // 图形的包络线相交
                List<SimpleFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
                Iterator<SimpleFeature> iter = envelopeIntersections.iterator();
                while (iter.hasNext()) {
                    SimpleFeature feature1 = iter.next();
                    Geometry targetGeo = (Geometry) feature1.getDefaultGeometry();
                    // 判断图形是不是真的相交
                    if (geom2.intersects(targetGeo)) {
                        Geometry geomOut = geom2.intersection(targetGeo);
                        if (geomOut != null && !geomOut.isEmpty()) {
                            SimpleFeature featureOut = writer.next();
                            featureOut.setAttribute("the_geom", geomOut);
                            for (int i = 0; i < fields1.size(); i++) {
                                Map<String, String> map = fields1.get(i);
                                String fieldShp = map.get("fieldShp").toString();
                                String fieldNew = map.get("fieldNew").toString();
                                if (fieldNew.length() < 10) {
                                    featureOut.setAttribute(fieldNew, feature1.getAttribute(fieldShp));
                                }

                            }
                            for (int i = 0; i < fields2.size(); i++) {
                                Map map = fields2.get(i);
                                String fieldShp = map.get("fieldShp").toString();
                                String fieldNew = map.get("fieldNew").toString();
                                if (fieldNew.length() < 10) {
                                    featureOut.setAttribute(fieldNew, feature2.getAttribute(fieldShp));
                                }
                            }
                            writer.write();
                            intersectResults.add(featureOut);
                        }
                    }
                }
                System.out.println(String.format("DKID: %s ,叠加的管制区数量为: %d ", id2, intersectResults.size()));
            }
            writer.close();
            ds.dispose();

            itertor2.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 空间相交操作
     *
     * @param inGeoJson1  被叠加图层（建议这个图层为多数据层，它将建空间索引）的GeoJson对象
     * @param inGeoJson2  叠加范围的GeoJson对象
     * @return
     * @throws Exception
     */
    public static String spatialIntersect(GeoJson inGeoJson1, GeoJson inGeoJson2,String encoding) throws Exception {

        int feaCount1 = inGeoJson1.getFeatures().size();
        int feaCount2 = inGeoJson2.getFeatures().size();
        if (feaCount1 == 0 || feaCount2 == 0) {
            return "";
        }

        // 2-GeoJson对象转换为Polygon 图形Wkt
        String geoType = inGeoJson1.getFeatures().get(0).getGeometry().getType();
        System.out.println();
        System.out.println("--->geoType: " + geoType);
        System.out.println("--->1，读取GeoJson图形");

        List<StgeoFeature> stgeoFea1 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson1);// 被叠加的数据
        List<StgeoFeature> stgeoFea2 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson2);// 叠加范围

        System.out.println(String.format("--->被擦除的数据 size : %d ", stgeoFea1.size()));
        // 3-遍历被叠加的图层数据（批而未供），建立空间索引
        System.out.println();
        System.out.println("--->2，建立空间索引");
        Quadtree quadTree = new Quadtree();
        Iterator<StgeoFeature> stgeoIterator1 = stgeoFea1.iterator();
        while (stgeoIterator1.hasNext()) {
            StgeoFeature stgeofea = stgeoIterator1.next();
            Geometry geom1 = (Geometry) stgeofea.getGeometry();
            Envelope itemEnv = geom1.getEnvelopeInternal();

            quadTree.insert(itemEnv, stgeofea);
        }

        System.out.println();
        System.out.println("--->3，Intersect相交判断");
        // 通过初步判断，获取哪些图形被擦除数据inGeoJson1与擦除范围inGeoJson2相交
        Set<StgeoFeature> intersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        for (int i = 0; i < stgeoFea2.size(); i++) {
            StgeoFeature stFea2 = stgeoFea2.get(i);
            Geometry geom2 = stFea2.getGeometry();

            // 图形的包络线相交
            List<StgeoFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
            System.out.println(
                    String.format("---quadTree->query, envelopeIntersections size: %d", envelopeIntersections.size()));
            int envelopeIntersectSize = envelopeIntersections.size();
            for (int j = 0; j < envelopeIntersectSize; j++) {
                StgeoFeature stFea1 = envelopeIntersections.get(j);
                Geometry geom1 = stFea1.getGeometry();
                // StgeoFeature重载了hashCode代码。采用空间判断是否相交进行数据类
                if (geom1.intersects(geom2)) {
                    intersectSTGeoFeaSet.add(stFea1);
                }
            }
        }
        System.out.println(String.format("--->3.1 intersectSTGeoFeaSet size : %d ", intersectSTGeoFeaSet.size()));

        //4-属性字段的构建
        System.out.println();
        System.out.println("--->4 属性字段的构建 ");
        /**
         * mapFields记录的是两个图层的属性名称， 在处理第二个图层的时候，如果已经有了这个名称， 会在字段后面加‘_1’予以区分
         * fields1为图层1的字段 fields2为图层2的字段
         */
        Map<String, String> mapFields = new HashMap();
        List<Map> fields1 = new ArrayList();
        List<Map> fields2 = new ArrayList();

        StringBuilder sb = new StringBuilder();
        //构建FeatureTypeSchema，包括两个图层的属性信息
        String featureTypeSchema = "geometry:Polygon";
        Map<String, Object> props1 = stgeoFea1.get(0).getProperties();
        Map<String, Object> props2 = stgeoFea2.get(0).getProperties();
        for (Map.Entry<String, Object> prop : props1.entrySet()) {
            String name = prop.getKey().toLowerCase();
            Object val = prop.getValue();
            String entType = "String";
            if (StringUtil.isNumeric(val == null ? "" : val.toString())) {
                entType = "Double";
            }

            mapFields.put(name, entType);
            if (!"shape".equalsIgnoreCase(name) && !"shape_area".equalsIgnoreCase(name)
                    && !"shape_length".equalsIgnoreCase(name)) {
                sb.append(String.format("%s:%s", name, entType));
                // sb.append(String.format("%s:%s", name, entType));
                sb.append(",");
            }
        }
        for (Map.Entry<String, Object> prop : props2.entrySet()) {
            String name = prop.getKey().toLowerCase();
            Object val = prop.getValue();

            String entType = "String";
            if (StringUtil.isNumeric(val == null ? "" : val.toString())) {
                entType = "Double";
            }
            //重复字段
            String _name = name;
            if (mapFields.containsKey(name)) {
                _name = _name + "_1";
            }
            mapFields.put(name, entType);
            if (!"shape".equalsIgnoreCase(name) && !"shape_area".equalsIgnoreCase(name)
                    && !"shape_length".equalsIgnoreCase(name)) {
                sb.append(String.format("%s:%s", name, entType));
                // sb.append(String.format("%s:%s", name, entType));
                sb.append(",");
            }
        }
        sb.append(String.format("%s:%s,", "shp_area", "Double"));
        sb.append(String.format("%s:%s", "shp_leng", "Double"));
        // sb.deleteCharAt(sb.length() - 1);
        featureTypeSchema = featureTypeSchema + "," + sb.toString();

        SimpleFeatureType TYPE = DataUtilities.createType("Link", featureTypeSchema);
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter writer = new WKTWriter();
        FeatureJSON fjson = new FeatureJSON();

        List<SimpleFeature> features = new ArrayList<>();
        SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);

        //5-空间叠加分析，保留擦除后的那部分图形
        System.out.println();
        System.out.println("--->5 空间叠加分析，保留擦除后的那部分图形");
        Iterator<StgeoFeature> iter2 = stgeoFea2.iterator();
        while (iter2.hasNext()) {
            StgeoFeature stFea2 = iter2.next();
            Geometry geom2 = stFea2.getGeometry();

            for (StgeoFeature stFea1 : intersectSTGeoFeaSet) {
                Map<String, Object> properties1 = stFea1.getProperties(); // 属性集合

                Geometry geom1 = stFea1.getGeometry();
                // 相交叠加分析的图形结果
                Geometry intersectionGeom = geom1.intersection(geom2);
                String intersectionGeomType= intersectionGeom.getGeometryType();
                if (intersectionGeom != null && !intersectionGeom.isEmpty()) {
                    double area_intersect = intersectionGeom.getArea();
                    double length_intersect = intersectionGeom.getLength();

                    String wkt = writer.write(intersectionGeom);
                    if ("polygon".equalsIgnoreCase(intersectionGeomType)) {
                        // 转换wkt为polygon
                        Polygon polygon = (Polygon) reader.read(wkt);

                        featureBuilder.add(polygon);

                        SimpleFeature feature = featureBuilder.buildFeature(null);
                        // 属性集合
                        for (Map.Entry<String, Object> prop : properties1.entrySet()) {
                            String name = prop.getKey().toLowerCase();
                            Object val = prop.getValue();
                            String attrVal = val == null ? "" : val.toString();
                            // String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");

                            if ("shape".equalsIgnoreCase(name) || "geom".equalsIgnoreCase(name)) {
                                continue;
                            } else if ("shape_area".equalsIgnoreCase(name)) {
                                //feature.setAttribute(name, shape_area);
                                feature.setAttribute("shp_area", area_intersect);
                            } else if ("shape_length".equalsIgnoreCase(name)) {
                                feature.setAttribute("shp_leng", length_intersect);
                            } else {
                                feature.setAttribute(name, attrVal);
                            }
                        }
                        //feature.setAttribute("shape_area", area_diff);
                        //feature.setAttribute("shape_length", length_diff);

                        features.add(feature);
                    } else if ("multipolygon".equalsIgnoreCase(intersectionGeomType)) {
                        MultiPolygon multiPolygon = (MultiPolygon) reader.read(wkt);

                        List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multiPolygon);
                        for (int i = 0; i < polygons.size(); i++) {
                            Polygon polygon = polygons.get(i);

                            featureBuilder.add(polygon);
                            SimpleFeature feature = featureBuilder.buildFeature(null);
                            // 属性集合
                            for (Map.Entry<String, Object> prop : properties1.entrySet()) {
                                String name = prop.getKey().toLowerCase();
                                Object val = prop.getValue();
                                String attrVal = val == null ? "" : val.toString();
                                // String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");

                                if ("shape".equalsIgnoreCase(name) || "geom".equalsIgnoreCase(name)) {
                                    continue;
                                } else if ("shape_area".equalsIgnoreCase(name)) {
                                    //feature.setAttribute(name, shape_area);
                                    feature.setAttribute("shp_area", area_intersect);
                                } else if ("shape_length".equalsIgnoreCase(name)) {
                                    feature.setAttribute("shp_leng", length_intersect);
                                } else {
                                    feature.setAttribute(name, attrVal);
                                }
                            }
                            //feature.setAttribute("shape_area", area_diff);
                            //feature.setAttribute("shape_length", length_diff);

                            features.add(feature);
                        }
                    }
                }
            }
        }

        // 转换为GeoJson
        System.out.println("--->6，将擦除后的图形转换为GeoJson");
        StringWriter strWriter = new StringWriter();
        fjson.writeFeatureCollection(collection, strWriter);
        String jsonStr = strWriter.toString();

        return jsonStr;
    }


    /**
     * 空间擦除操作
     *
     * @param inputPath1 待擦除数据的shp物理路径
     * @param inputPath2 擦除范围数据的shp物理路径
     * @param outputPath 新生成的结果数据的shp输出物理路径
     * @throws Exception
     */
    public static void spatialDifference(String inputPath1, String inputPath2, String outputPath, String encoding) throws Exception {

        try {
            File inputFile1 = new File(inputPath1);
            File inputFile2 = new File(inputPath2);

            ShapefileDataStore shpDataStore1 = new ShapefileDataStore(inputFile1.toURL());
            ShapefileDataStore shpDataStore2 = new ShapefileDataStore(inputFile2.toURL());

            // 属性编码
            Charset charset = Charset.forName("GBK");
            shpDataStore1.setCharset(charset);
            shpDataStore2.setCharset(charset);
            String typeName1 = shpDataStore1.getTypeNames()[0];
            String typeName2 = shpDataStore2.getTypeNames()[0];

            SimpleFeatureSource featureSource1 = shpDataStore1.getFeatureSource(typeName1);
            SimpleFeatureSource featureSource2 = shpDataStore2.getFeatureSource(typeName2);
            SimpleFeatureCollection featureCollection1 = featureSource1.getFeatures();
            SimpleFeatureCollection featureCollection2 = featureSource2.getFeatures();

            SimpleFeatureType sfType = featureSource1.getSchema();
            CoordinateReferenceSystem targetCRS = sfType.getCoordinateReferenceSystem();
            /**
             * mapFields记录的是两个图层的属性名称， 在处理第二个图层的时候，如果已经有了这个名称， 会在字段后面加‘_1’予以区分
             * fields1为图层1的字段 fields2为图层2的字段
             */
            Map<String, Class> mapFields = new HashMap<String, Class>();
            List<Map<String, String>> fields1 = new ArrayList<Map<String, String>>();

            // 2-待裁剪擦除的数据集合
            SimpleFeatureType featureType1 = featureCollection1.getSchema();
            List<AttributeDescriptor> attrList1 = featureType1.getAttributeDescriptors();
            for (int i = 0; i < attrList1.size(); i++) {
                AttributeDescriptor attr = attrList1.get(i);
                String name = attr.getName().toString();
                Class type = attr.getType().getBinding();
                if (name != "the_geom") {
                    mapFields.put(name, type);

                    Map<String, String> map = new HashMap<String, String>();
                    map.put("fieldShp", name);
                    map.put("fieldNew", name);
                    fields1.add(map);
                }
            }

            // 3-遍历被叠加的图层数据（建设用地管制区），建立空间索引
            Quadtree quadTree = new Quadtree();
            SimpleFeatureIterator iterator1 = featureCollection1.features();
            while (iterator1.hasNext()) {
                SimpleFeature feature1 = iterator1.next();
                Geometry geom1 = (Geometry) feature1.getDefaultGeometry();
                Envelope itemEnv = geom1.getEnvelopeInternal();

                quadTree.insert(itemEnv, feature1);
            }

            // 3-创建输出文件
            File outputFile = new File(outputPath);
            Map<String, Serializable> params = new HashMap<String, Serializable>();
            params.put(ShapefileDataStoreFactory.URLP.key, outputFile.toURI().toURL());
            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
            // 定义图形信息和属性信息
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.setCRS(targetCRS);
            tb.setName("shapefile");
            tb.add("the_geom", MultiPolygon.class);
            for (String key : mapFields.keySet()) {
                tb.add(key, mapFields.get(key));
            }
            ds.createSchema(tb.buildFeatureType());
            // 设置编码
            ds.setCharset(charset);
            // 设置Writer
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0],
                    Transaction.AUTO_COMMIT);

            // 4-首先循环inputPath2要数，然后遍历inputPath2逐个进行擦除
            SimpleFeatureIterator itertor2 = featureCollection2.features();
            while (itertor2.hasNext()) {
                SimpleFeature feature2 = itertor2.next();
                Geometry geom2 = (Geometry) feature2.getDefaultGeometry();
                String id2 = feature2.getID();

                // 图形的包络线相交
                List<SimpleFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
                Iterator<SimpleFeature> itertor1 = envelopeIntersections.iterator();
                List<SimpleFeature> diffResults = new ArrayList<SimpleFeature>();
                while (itertor1.hasNext()) {
                    SimpleFeature feature1 = itertor1.next();
                    Geometry targetGeo = (Geometry) feature1.getDefaultGeometry();

                    // 4.1-相交图形，仅保留擦除后的部分图形内容
                    if (geom2.intersects(targetGeo)) {
                        Geometry geomOut = targetGeo.difference(geom2);
                        if (geomOut != null && !geomOut.isEmpty()) {
                            double newFeaArea = geomOut.getArea(); // 擦除后的面积
                            double newFeaLength = geomOut.getLength(); // 擦除后的周长

                            SimpleFeature featureOut = writer.next();
                            featureOut.setAttribute("the_geom", geomOut);
                            for (int i = 0; i < fields1.size(); i++) {
                                Map map = fields1.get(i);
                                String fieldShp = map.get("fieldShp").toString();
                                String fieldNew = map.get("fieldNew").toString();

                                if (fieldNew.length() < 10) {
                                    if ("shape_area".equalsIgnoreCase(fieldShp)) {
                                        featureOut.setAttribute(fieldNew, newFeaArea);
                                    } else if ("shape_length".equalsIgnoreCase(fieldShp)) {
                                        featureOut.setAttribute(fieldNew, newFeaLength);
                                    } else {
                                        featureOut.setAttribute(fieldNew, feature1.getAttribute(fieldShp));
                                    }
                                }
                            }

                            writer.write();
                            diffResults.add(featureOut);
                        }
                    } else {
                        // 4.2-不相交的数据集，直接全部保留
                        SimpleFeature featureOut = writer.next();
                        featureOut.setAttribute("the_geom", targetGeo);
                        for (int i = 0; i < fields1.size(); i++) {
                            Map map = fields1.get(i);
                            String fieldShp = map.get("fieldShp").toString();
                            String fieldNew = map.get("fieldNew").toString();
                            if (fieldNew.length() < 10) {
                                featureOut.setAttribute(fieldNew, feature1.getAttribute(fieldShp));
                            }
                        }

                        writer.write();
                        diffResults.add(featureOut);
                    }
                }
                System.out.println(String.format("DKID: %s ,擦除完成。剩余数据集个数: %d ", id2, diffResults.size()));
            }
            writer.close();
            ds.dispose();

            itertor2.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 空间擦除操作
     *
     * @param inGeoJson1
     * @param inGeoJson2
     * @param encoding
     * @return
     * @throws Exception
     */
    public static String spatialDifference(GeoJson inGeoJson1, GeoJson inGeoJson2, String encoding) throws Exception {

        int feaCount1 = inGeoJson1.getFeatures().size();
        int feaCount2 = inGeoJson2.getFeatures().size();
        if (feaCount1 == 0 || feaCount2 == 0) {
            return "";
        }

        // 2-GeoJson对象转换为Polygon 图形Wkt
        String geoType = inGeoJson1.getFeatures().get(0).getGeometry().getType();
        System.out.println();
        System.out.println("--->geoType: " + geoType);
        System.out.println("--->1，读取GeoJson图形");

        List<StgeoFeature> stgeoFea1 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson1);// 被擦除的数据
        List<StgeoFeature> stgeoFea2 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson2);// 擦除范围

        System.out.println(String.format("--->被擦除的数据 size : %d ", stgeoFea1.size()));
        // 3-遍历被叠加的图层数据（批而未供），建立空间索引
        System.out.println();
        System.out.println("--->2，建立空间索引");
        Quadtree quadTree = new Quadtree();
        Iterator<StgeoFeature> stgeoIterator1 = stgeoFea1.iterator();
        while (stgeoIterator1.hasNext()) {
            StgeoFeature stgeofea = stgeoIterator1.next();
            Geometry geom1 = (Geometry) stgeofea.getGeometry();
            Envelope itemEnv = geom1.getEnvelopeInternal();

            quadTree.insert(itemEnv, stgeofea);
        }

        System.out.println();
        System.out.println("--->3，相交判断");
        // 通过初步判断，获取哪些图形被擦除数据inGeoJson1与擦除范围inGeoJson2相交
        Set<StgeoFeature> intersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        for (int i = 0; i < stgeoFea2.size(); i++) {
            StgeoFeature stFea2 = stgeoFea2.get(i);
            Geometry geom2 = stFea2.getGeometry();

            // 图形的包络线相交
            List<StgeoFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
            System.out.println(String.format("---quadTree->query, envelopeIntersections size: %d", envelopeIntersections.size()));
            int envelopeIntersectSize = envelopeIntersections.size();
            for (int j = 0; j < envelopeIntersectSize; j++) {
                StgeoFeature stFea1 = envelopeIntersections.get(j);
                Geometry geom1 = stFea1.getGeometry();
                // StgeoFeature重载了hashCode代码。采用空间判断是否相交进行数据类
                if (geom1.intersects(geom2)) {
                    intersectSTGeoFeaSet.add(stFea1);
                }
            }
        }
        System.out.println(String.format("--->3.1 intersectSTGeoFeaSet size : %d ", intersectSTGeoFeaSet.size()));

        // 获取未相交的部分
        Set<StgeoFeature> nullIntersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        for (int j = 0; j < stgeoFea1.size(); j++) {
            StgeoFeature stFea1 = stgeoFea1.get(j);
            if ( !intersectSTGeoFeaSet.contains(stFea1) ) {
                nullIntersectSTGeoFeaSet.add(stFea1);
            }
        }
        System.out.println(String.format("--->3.2 nullIntersectSTGeoFeaSet size : %d ", nullIntersectSTGeoFeaSet.size()));

        System.out.println();
        System.out.println("--->4，擦除计算");
        StringBuilder sb = new StringBuilder();
        // 构建FeatureTypeSchema
        String featureTypeSchema = "geometry:Polygon";
        Map<String, Object> props = stgeoFea1.get(0).getProperties();
        for (Map.Entry<String, Object> prop : props.entrySet()) {
            String name = prop.getKey().toLowerCase();
            /*
             * Object entValue = prop.getValue(); Class<? extends Object> entType;
             *
             * //null if(StringUtil.isNullOrEmpty(entValue.toString())) { entType=
             * String.class; }else { entType = entValue.getClass(); }
             */

            if (!"shape".equalsIgnoreCase(name) && !"shape_area".equalsIgnoreCase(name)
                    && !"shape_length".equalsIgnoreCase(name)) {
                sb.append(String.format("%s:%s", name, "String"));
                // sb.append(String.format("%s:%s", name, entType));
                sb.append(",");
            }
        }
        sb.append(String.format("%s:%s,", "shape_area", "Double"));
        sb.append(String.format("%s:%s", "shape_length", "Double"));
        // sb.deleteCharAt(sb.length() - 1);
        featureTypeSchema = featureTypeSchema + "," + sb.toString();

        SimpleFeatureType TYPE = DataUtilities.createType("Link", featureTypeSchema);
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter writer = new WKTWriter();
        FeatureJSON fjson = new FeatureJSON();

        List<SimpleFeature> features = new ArrayList<>();
        SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
        // 第1部分---全部保留
        System.out.println("--->4.1，全部保留");
        for (StgeoFeature stFea1 : nullIntersectSTGeoFeaSet) {
            Map<String, Object> properties = stFea1.getProperties(); // 属性集合
            Geometry geom = stFea1.getGeometry(); // 图形
            System.out.println();

            String wkt = writer.write(geom);
            String geoTypeOfNullIntersect = geom.getGeometryType();
            if("polygon".equalsIgnoreCase(geoTypeOfNullIntersect)){
                // 转换wkt为polygon
                Polygon polygon = (Polygon) reader.read(wkt);
                featureBuilder.add(polygon);
                SimpleFeature feature = featureBuilder.buildFeature(null);
                // 属性集合
                for (Map.Entry<String, Object> prop : properties.entrySet()) {
                    String name = prop.getKey().toLowerCase();
                    Object val = prop.getValue();
                    String attrVal = val == null ? "" : val.toString();
                    // String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");
                    System.out.println(String.format("-->prop name: %s, val: %s", name, attrVal));

                    if ("shape".equalsIgnoreCase(name)) {
                        continue;
                    } else if ("shape_area".equalsIgnoreCase(name)) {
                        double shape_area = Double.parseDouble(attrVal);
                        feature.setAttribute(name, shape_area);
                    } else if ("shape_length".equalsIgnoreCase(name)) {
                        double shape_length = Double.parseDouble(attrVal);
                        feature.setAttribute(name, shape_length);
                    } else {
                        feature.setAttribute(name, attrVal);
                    }
                }

                features.add(feature);
            }else if("multipolygon".equalsIgnoreCase(geoTypeOfNullIntersect)){
                MultiPolygon multiPolygon = (MultiPolygon) reader.read(wkt);
                List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multiPolygon);
                for (int i = 0; i < polygons.size(); i++) {
                    Polygon polygon = polygons.get(i);

                    featureBuilder.add(polygon);
                    SimpleFeature feature = featureBuilder.buildFeature(null);
                    // 属性集合
                    for (Map.Entry<String, Object> prop : properties.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        Object val = prop.getValue();
                        String attrVal = val == null ? "" : val.toString();
                        // String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");
                        System.out.println(String.format("-->prop name: %s, val: %s", name, attrVal));

                        if ("shape".equalsIgnoreCase(name)) {
                            continue;
                        } else if ("shape_area".equalsIgnoreCase(name)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(name, shape_area);
                        } else if ("shape_length".equalsIgnoreCase(name)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(name, shape_length);
                        } else {
                            feature.setAttribute(name, attrVal);
                        }
                    }

                    features.add(feature);
                }
            }

        }
        // 第2部分---保留擦除后的那部分图形
        System.out.println("--->4.2，保留擦除后的那部分图形");
        Iterator<StgeoFeature> iter2 = stgeoFea2.iterator();
        while (iter2.hasNext()) {
            Geometry geom2 = iter2.next().getGeometry();

            for (StgeoFeature stFea1 : intersectSTGeoFeaSet) {
                Map<String, Object> properties = stFea1.getProperties(); // 属性集合

                Geometry geom1 = stFea1.getGeometry();

                // 擦除之后的图形结果
                Geometry diffGeom = geom1.difference(geom2);
                String diffGeomGeometryType = diffGeom.getGeometryType();
                if (diffGeom != null && !diffGeom.isEmpty()) {
                    double area_diff = diffGeom.getArea();
                    double length_diff = diffGeom.getLength();

                    String wkt = writer.write(diffGeom);
                    // 转换wkt为polygon
                    if("polygon".equalsIgnoreCase(diffGeomGeometryType)){
                        Polygon polygon = (Polygon) reader.read(wkt);
                        featureBuilder.add(polygon);

                        SimpleFeature feature = featureBuilder.buildFeature(null);
                        // 属性集合
                        for (Map.Entry<String, Object> prop : properties.entrySet()) {
                            String name = prop.getKey().toLowerCase();
                            Object val = prop.getValue();
                            String attrVal = val == null ? "" : val.toString();
                            // String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");

                            if ("shape".equalsIgnoreCase(name)) {
                                continue;
                            } else if ("shape_area".equalsIgnoreCase(name)) {
                                double shape_area = Double.parseDouble(attrVal);
                                feature.setAttribute(name, shape_area);
                            } else if ("shape_length".equalsIgnoreCase(name)) {
                                double shape_length = Double.parseDouble(attrVal);
                                feature.setAttribute(name, shape_length);
                            } else {
                                feature.setAttribute(name, attrVal);
                            }
                        }
                        feature.setAttribute("shape_area", area_diff);
                        feature.setAttribute("shape_length", length_diff);

                        features.add(feature);
                    }else if("multipolygon".equalsIgnoreCase(diffGeomGeometryType)) {
                        MultiPolygon multiPolygon = (MultiPolygon) reader.read(wkt);
                        List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multiPolygon);
                        for (int i = 0; i < polygons.size(); i++) {
                            Polygon polygon = polygons.get(i);
                            featureBuilder.add(polygon);

                            SimpleFeature feature = featureBuilder.buildFeature(null);
                            // 属性集合
                            for (Map.Entry<String, Object> prop : properties.entrySet()) {
                                String name = prop.getKey().toLowerCase();
                                Object val = prop.getValue();
                                String attrVal = val == null ? "" : val.toString();
                                // String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");

                                if ("shape".equalsIgnoreCase(name)) {
                                    continue;
                                } else if ("shape_area".equalsIgnoreCase(name)) {
                                    double shape_area = Double.parseDouble(attrVal);
                                    feature.setAttribute(name, shape_area);
                                } else if ("shape_length".equalsIgnoreCase(name)) {
                                    double shape_length = Double.parseDouble(attrVal);
                                    feature.setAttribute(name, shape_length);
                                } else {
                                    feature.setAttribute(name, attrVal);
                                }
                            }
                            feature.setAttribute("shape_area", area_diff);
                            feature.setAttribute("shape_length", length_diff);

                            features.add(feature);
                        }
                    }
                }
            }
        }

        // 转换为GeoJson
        System.out.println("--->5，将擦除后的图形转换为GeoJson");
        StringWriter strWriter = new StringWriter();
        fjson.writeFeatureCollection(collection, strWriter);
        String jsonStr = strWriter.toString();

        return jsonStr;
    }



    /**
     * 空间Union操作
     *
     * 属性字段名中更改字符“.”为“_”,其余字段名原样全部保留。
     *
     * @param inGeoJson1
     * @param inGeoJson2

     * @return
     * @throws Exception
     */
    public static String spatialUnion(GeoJson inGeoJson1, GeoJson inGeoJson2 ) throws Exception {

        int feaCount1 = inGeoJson1.getFeatures().size();
        int feaCount2 = inGeoJson2.getFeatures().size();
        if(feaCount1==0 || feaCount2==0) {
            return "";
        }

        //2-GeoJson对象转换为Polygon 图形Wkt
        String geoType1 = inGeoJson1.getFeatures().get(0).getGeometry().getType();
        System.out.println();
        System.out.println("--->geoType1: "+ geoType1);
        System.out.println("--->1，读取GeoJson图形");

        List<StgeoFeature> stgeoFea1 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson1);//被擦除的数据
        List<StgeoFeature> stgeoFea2 = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson2);//擦除范围

        System.out.println(String.format("--->被擦除的数据 size : %d ",stgeoFea1.size()));
        //3-遍历被叠加的图层数据（批而未供），建立空间索引
        System.out.println();
        System.out.println("--->2，建立空间索引");
        Quadtree quadTree = new Quadtree();
        Iterator<StgeoFeature> stgeoIterator1 = stgeoFea1.iterator();
        while (stgeoIterator1.hasNext()) {
            StgeoFeature stgeofea = stgeoIterator1.next();
            Geometry geom1 = (Geometry) stgeofea.getGeometry();
            Envelope itemEnv = geom1.getEnvelopeInternal();

            quadTree.insert(itemEnv, stgeofea);
        }

        System.out.println();
        System.out.println("--->3，相交判断");
        //通过初步判断，获取哪些图形被擦除数据inGeoJson1与擦除范围inGeoJson2相交
        Map<StgeoFeature,Set<StgeoFeature>> intersectSTGeoFeaSets = new HashMap<StgeoFeature,Set<StgeoFeature>>();
        for(int i=0; i<stgeoFea2.size(); i++) {
            StgeoFeature stFea2 = stgeoFea2.get(i);
            Geometry geom2 = stFea2.getGeometry();

            //通过空间索引，快速计算图形的包络线相交
            Set<StgeoFeature> intersectSTGeoFeaSet= new HashSet<StgeoFeature>();
            List<StgeoFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
            System.out.println(String.format("---quadTree->query, envelopeIntersections size: %d", envelopeIntersections.size()));
            int envelopeIntersectSize = envelopeIntersections.size();
            for(int j=0; j<envelopeIntersectSize; j++) {
                StgeoFeature stFea1 = envelopeIntersections.get(j);

                Geometry geom1 = stFea1.getGeometry();
                //StgeoFeature重载了hashCode代码。采用空间判断是否相交进行数据类
                if( geom1.intersects(geom2) ) {
                    intersectSTGeoFeaSet.add(stFea1);
                }
            }
            System.out.println(String.format("--->3.1 intersectSTGeoFeaSet size : %d ",intersectSTGeoFeaSet.size()));
            intersectSTGeoFeaSets.put(stFea2, intersectSTGeoFeaSet);
        }

        //获取未相交的部分
        Set<StgeoFeature> nullIntersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        //1.stgeoFea1
        for(int j=0; j<stgeoFea1.size(); j++) {
            StgeoFeature stFea1 = stgeoFea1.get(j);
            stFea1.setLayerFlag("1");
            for(Map.Entry<StgeoFeature, Set<StgeoFeature>> ent: intersectSTGeoFeaSets.entrySet() ) {
                Set<StgeoFeature> entVals = ent.getValue();
                if( !entVals.contains(stFea1) ) {
                    nullIntersectSTGeoFeaSet.add(stFea1);
                }
            }
        }
        //2.stgeoFea2
        for (int j = 0; j < stgeoFea2.size(); j++) {
            StgeoFeature stFea2 = stgeoFea2.get(j);
            stFea2.setLayerFlag("2");
            //很重要
            if (!intersectSTGeoFeaSets.containsKey(stFea2)) {
                nullIntersectSTGeoFeaSet.add(stFea2);
            }
        }
        System.out.println(String.format("--->3.2 nullIntersectSTGeoFeaSet size : %d ", nullIntersectSTGeoFeaSet.size()));


        System.out.println();
        System.out.println("--->4，构建字段结构SimpleFeatureType");
        StringBuilder sb = new StringBuilder();
        //字段类型集合
        Map<String,String> mapFieldTypes = new HashMap<String,String>();

        //构建FeatureTypeSchema
        String featureTypeSchema = "geometry:Polygon";
        Map<String,Object> props1 = stgeoFea1.get(0).getProperties();
        Map<String,Object> props2 = stgeoFea2.get(0).getProperties();
        for(Map.Entry<String, Object> prop: props1.entrySet()) {
            String name = prop.getKey().toLowerCase();
            String subName = name.replace('.', '_');
            Object val = prop.getValue();

            String entType = "String";
            if(StringUtil.isNullOrEmpty(val)) {
                entType = "String";
            }
            else if (StringUtil.isNumeric3(val.toString())) {
                entType = "Double";
            }

            if( !"shape".equalsIgnoreCase(subName) && !"shape_area".equalsIgnoreCase(subName) &&  !"shape_leng".equalsIgnoreCase(subName)) {
                if(!mapFieldTypes.containsKey(subName)) {
                    mapFieldTypes.put(subName, entType);
                }
            }
        }
        //图层2的字段新映射表
        Map<String,String> props2FieldMaps = new HashMap<String,String>();
        for(Map.Entry<String, Object> prop: props2.entrySet()) {
            String name = prop.getKey().toLowerCase();
            String subName= name.replace('.', '_');
            Object val = prop.getValue();

            String fieldType = "String";
            if(StringUtil.isNullOrEmpty(val) ) {
                fieldType = "String";;
            }

            if (StringUtil.isNumeric3(val.toString())) {
                fieldType = "Double";
            }
            if( !"shape".equalsIgnoreCase(subName) && !"shape_area".equalsIgnoreCase(subName) &&  !"shape_leng".equalsIgnoreCase(subName)) {
                //是否已存在该字段名
                if(mapFieldTypes.containsKey(subName)) {
                    String newName = subName + "_1";

                    mapFieldTypes.put(newName, fieldType);
                    props2FieldMaps.put(subName, newName);
                }else {
                    mapFieldTypes.put(subName, fieldType);
                    props2FieldMaps.put(subName, subName);
                }
            }
        }

        //根据mapFieldTypes构建字段TYPE
        System.out.println("mapfields: "+mapFieldTypes.toString());
        for(Map.Entry<String, String> fieldEnt: mapFieldTypes.entrySet()) {
            String fieldName = fieldEnt.getKey();
            String fieldType = fieldEnt.getValue();

            sb.append(String.format("%s:%s", fieldName, fieldType));
            sb.append(",");
        }
        // "String"、"Integer"、"Double"
        sb.append(String.format("%s:%s,", "shape_area", "Double"));
        sb.append(String.format("%s:%s,", "shape_leng", "Double"));
        sb.append(String.format("%s:%s", "union_flag", "String"));

        //sb.deleteCharAt(sb.length() - 1);
        featureTypeSchema = featureTypeSchema +","+ sb.toString();

        SimpleFeatureType TYPE =  DataUtilities.createType("Link", featureTypeSchema);
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        //1.第1部分---全部保留
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter writer = new WKTWriter();
        FeatureJSON fjson = new FeatureJSON();

        List<SimpleFeature> features = new ArrayList<>();
        SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
        System.out.println("--->5.1，全部保留");
        for(StgeoFeature stFea: nullIntersectSTGeoFeaSet) {
            Map<String,Object> properties = stFea.getProperties(); //属性集合
            Geometry geom = stFea.getGeometry(); //图形
            String unionFlag = stFea.getLayerFlag();//数据图层源信息
            System.out.println();

            String  geomType= geom.getGeometryType();
            String wkt = writer.write(geom);
            if("polygon".equalsIgnoreCase(geomType)) {
                //转换wkt为polygon
                Polygon polygon = (Polygon) reader.read(wkt);
                featureBuilder.add(polygon);
            }else if("multipolygon".equalsIgnoreCase(geomType)) {
                MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                for(Polygon p: polygons) {
                    featureBuilder.add(p);
                }
            }
            SimpleFeature feature = featureBuilder.buildFeature(null);

            //属性集合
            for(Map.Entry<String, Object>  prop : properties.entrySet()) {
                String fieldName = prop.getKey().toLowerCase();
                String subName = fieldName.replace('.', '_');//修正后的字段名
                String fieldType = mapFieldTypes.get(subName);//字段类型

                Object val = prop.getValue();
                String attrVal = "";
                if(val==null) {
                    attrVal="";
                }else {
                    attrVal=val.toString();
                }

                //String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");
                System.out.println(String.format("-->prop name: %s, val: %s", subName, attrVal));

                if( "shape".equalsIgnoreCase(subName)) {
                    continue;
                }else if("shape_area".equalsIgnoreCase(subName)) {
                    double shape_area = Double.parseDouble(attrVal);
                    feature.setAttribute(subName, shape_area);
                }
                else if("shape_leng".equalsIgnoreCase(subName)) {
                    double shape_length = Double.parseDouble(attrVal);
                    feature.setAttribute(subName, shape_length);
                }else {
                    if(mapFieldTypes.containsKey(subName)) {
                        if("String".equalsIgnoreCase(fieldType)) {
                            feature.setAttribute(subName, attrVal);
                        }
                        else if("Double".equalsIgnoreCase(fieldType)){
                            double numAttrVal=0.0;
                            if(StringUtil.isNumeric3(attrVal)) {
                                numAttrVal = Double.parseDouble(attrVal);
                            }
                            feature.setAttribute(subName, numAttrVal);
                        }

                    }
                }
            }

            feature.setAttribute("union_flag", unionFlag);

            features.add(feature);
        }

        System.out.println("--->5.2，保留擦除后的那部分图形： 分为3种情况逐一出来");
        for(Map.Entry<StgeoFeature, Set<StgeoFeature>> ent: intersectSTGeoFeaSets.entrySet()) {
            StgeoFeature stFea2 = ent.getKey();
            Set<StgeoFeature> intersectSTGeoFeaSet1 = ent.getValue();
            //key geometry
            Geometry geom2 = stFea2.getGeometry();
            Map<String,Object> properties2 = stFea2.getProperties();
            //第2部分---保留擦除后的那部分图形
            //2.1 获取Geom1内，且Geom2以外非公共部分
            System.out.println("------>1.获取Geom1内且Geom2以外，非公共部分");
            for(StgeoFeature stFea1: intersectSTGeoFeaSet1) {
                Map<String,Object> properties1 = stFea1.getProperties(); //属性集合
                Geometry geom1 = stFea1.getGeometry();

                Geometry diffGeom = geom1.difference(geom2);
                String diffGeomType =diffGeom.getGeometryType();
                double area_diff = diffGeom.getArea();
                double length_diff = diffGeom.getLength();

                String wkt = writer.write(diffGeom);
                if("polygon".equalsIgnoreCase(diffGeomType)) {
                    //转换wkt为polygon
                    Polygon polygon = (Polygon) reader.read(wkt);
                    featureBuilder.add(polygon);
                }else if("multipolygon".equalsIgnoreCase(diffGeomType)) {
                    MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                    List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                    for(Polygon p: polygons) {
                        featureBuilder.add(p);
                    }
                }

                SimpleFeature feature = featureBuilder.buildFeature(null);
                //属性集合
                for(Map.Entry<String, Object>  prop : properties1.entrySet()) {
                    String name = prop.getKey().toLowerCase();
                    String subName = name.replace('.', '_');
                    String fieldType = mapFieldTypes.get(subName);//字段类型

                    Object val = prop.getValue();
                    String attrVal = "";
                    if(val==null) {
                        attrVal="";
                    }else {
                        attrVal=val.toString();
                    }

                    if( "shape".equalsIgnoreCase(subName) ) {
                        continue;
                    }else if("shape_area".equalsIgnoreCase(subName)) {
                        double shape_area = Double.parseDouble(attrVal);
                        feature.setAttribute(subName, shape_area);
                    }else if("shape_leng".equalsIgnoreCase(subName)) {
                        double shape_length = Double.parseDouble(attrVal);
                        feature.setAttribute(subName, shape_length);
                    }else {
                        if(mapFieldTypes.containsKey(subName)) {
                            if("String".equalsIgnoreCase(fieldType)) {
                                feature.setAttribute(subName, attrVal);
                            }
                            else if("Double".equalsIgnoreCase(fieldType)){
                                double numAttrVal=0.0;
                                if(StringUtil.isNumeric3(attrVal)) {
                                    numAttrVal = Double.parseDouble(attrVal);
                                }
                                feature.setAttribute(subName, numAttrVal);
                            }
                        }
                    }
                }
                feature.setAttribute("shape_area", area_diff);
                feature.setAttribute("shape_leng", length_diff);
                feature.setAttribute("union_flag", "1");

                features.add(feature);
            }

            //2.2-获取与Geom2相交的公共部分
            System.out.println("------>2.获取Geom1内且Geom2相交后，共有部分");
            Set<Geometry> intersectGeoms = new HashSet<Geometry>();
            for(StgeoFeature stFea1: intersectSTGeoFeaSet1) {
                Map<String,Object> properties1 = stFea1.getProperties(); //属性集合
                Geometry geom1 = stFea1.getGeometry();

                //相交
                Geometry intersectGeom = geom1.intersection(geom2);
                String intersectGeomType = intersectGeom.getGeometryType();
                if( intersectGeom != null && !intersectGeom.isEmpty()  ) {
                    double area_diff = intersectGeom.getArea();
                    double length_diff = intersectGeom.getLength();

                    String wkt = writer.write(intersectGeom);
                    if("polygon".equalsIgnoreCase(intersectGeomType)) {
                        //转换wkt为polygon
                        Polygon polygon = (Polygon) reader.read(wkt);
                        featureBuilder.add(polygon);
                    }else if("multipolygon".equalsIgnoreCase(intersectGeomType)) {
                        MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                        List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                        for(Polygon p: polygons) {
                            featureBuilder.add(p);
                        }
                    }

                    SimpleFeature feature = featureBuilder.buildFeature(null);
                    //属性1集合
                    for(Map.Entry<String, Object>  prop : properties1.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName= name.replace('.', '_');
                        String fieldType = mapFieldTypes.get(subName);//字段类型

                        Object val = prop.getValue();
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(subName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(subName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(subName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(subName)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(subName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(subName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(subName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(subName, numAttrVal);
                                }
                            }
                        }
                    }
                    //属性2集合
                    for(Map.Entry<String, Object>  prop : properties2.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName = name.replace('.', '_');


                        //与prop1重复字段 prop1_1
                        String newName = subName;
                        if(props2FieldMaps.containsKey(subName)) {
                            newName = props2FieldMaps.get(subName);
                        }
                        String fieldType = mapFieldTypes.get(newName);//字段类型

                        Object val = prop.getValue();//字段值
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(newName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(newName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(name)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(newName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(newName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(newName, numAttrVal);
                                }
                            }
                        }
                    }

                    feature.setAttribute("shape_area", area_diff);
                    feature.setAttribute("shape_leng", length_diff);
                    feature.setAttribute("union_flag", "12");

                    features.add(feature);

                    intersectGeoms.add(intersectGeom);
                }
            }

            //2.3-获取与geom2相交公共以外的部分，即剩余图形
            System.out.println("------>3.获取与geom2相交,公共以外的部分，即剩余图形");
            Geometry diffGeom = geom2;
            for(Geometry intersectGeom: intersectGeoms) {
                //迭代擦除所有相交部分图形
                diffGeom = diffGeom.difference(intersectGeom);
            }
            String symDiffGeoType = diffGeom.getGeometryType();
            if(diffGeom != null && !diffGeom.isEmpty() ) {
                double area_diff = diffGeom.getArea();
                double length_diff = diffGeom.getLength();

                String wkt = writer.write(diffGeom);
                if("polygon".equalsIgnoreCase(symDiffGeoType)) {
                    //转换wkt为polygon
                    Polygon polygon = (Polygon) reader.read(wkt);
                    featureBuilder.add(polygon);

                    SimpleFeature feature = featureBuilder.buildFeature(null);
                    //属性集合
                    for(Map.Entry<String, Object>  prop : properties2.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName= name.replace('.', '_');

                        //与prop1重复字段
                        String newName = subName;
                        if(props2FieldMaps.containsKey(subName)) {
                            newName = props2FieldMaps.get(subName);
                        }

                        String fieldType = mapFieldTypes.get(newName);//字段类型

                        Object val = prop.getValue();//字段值
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(newName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(newName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(newName)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(newName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(newName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(newName, numAttrVal);
                                }
                            }
                        }
                    }
                    feature.setAttribute("shape_area", area_diff);
                    feature.setAttribute("shape_leng", length_diff);
                    feature.setAttribute("union_flag", "2");

                    features.add(feature);
                }
                else if("multipolygon".equalsIgnoreCase(symDiffGeoType)) {
                    //转换wkt为polygon
                    MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                    List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                    for(int i=0; i<polygons.size(); i++)
                    {
                        Polygon polygon = polygons.get(i);
                        featureBuilder.add(polygon);

                        SimpleFeature feature = featureBuilder.buildFeature(null);
                        //属性集合
                        for(Map.Entry<String, Object>  prop : properties2.entrySet()) {
                            String name = prop.getKey().toLowerCase();
                            String subName = name.replace('.', '_');
                            //与prop1重复字段
                            String newName = subName;
                            if(props2FieldMaps.containsKey(subName)) {
                                newName = props2FieldMaps.get(subName);
                            }
                            String fieldType = mapFieldTypes.get(newName);//字段类型
                            Object val = prop.getValue();//字段值
                            String attrVal = "";
                            if(val==null) {
                                attrVal="";
                            }else {
                                attrVal=val.toString();
                            }


                            if( "shape".equalsIgnoreCase(newName) || "id".equalsIgnoreCase(newName)) {
                                continue;
                            }else if("shape_area".equalsIgnoreCase(newName)) {
                                double shape_area = Double.parseDouble(attrVal);
                                feature.setAttribute(newName, shape_area);
                            }else if("shape_leng".equalsIgnoreCase(newName)) {
                                double shape_length = Double.parseDouble(attrVal);
                                feature.setAttribute(newName, shape_length);
                            }else {
                                if(mapFieldTypes.containsKey(newName)){
                                    if("String".equalsIgnoreCase(fieldType)) {
                                        feature.setAttribute(newName, attrVal);
                                    }
                                    else if("Double".equalsIgnoreCase(fieldType)){
                                        double numAttrVal=0.0;
                                        if(StringUtil.isNumeric3(attrVal)) {
                                            numAttrVal = Double.parseDouble(attrVal);
                                        }
                                        feature.setAttribute(newName, numAttrVal);
                                    }
                                }
                            }
                        }
                        feature.setAttribute("shape_area", area_diff);
                        feature.setAttribute("shape_leng", length_diff);
                        feature.setAttribute("union_flag", "2");

                        features.add(feature);
                    }
                }
            }
        }

        //转换为GeoJson
        System.out.println("--->6，将擦除后的图形转换为GeoJson");
        StringWriter strWriter = new StringWriter();
        fjson.writeFeatureCollection(collection, strWriter);
        String jsonStr = strWriter.toString();

        return jsonStr;
    }


    /**
     * 空间Union操作
     *
     * 属性字段名中更改字符“.”为“_”，同时根据bFirstAttributeSaved和bSecondAttributeSaved常量进行选择属性保存
     *
     * @param inGeoJson1
     * @param inGeoJson2

     * @return
     * @throws Exception
     */
    public static String spatialUnionEx(GeoJson inGeoJson1, GeoJson inGeoJson2 ) throws Exception {

        int feaCount1 = inGeoJson1.getFeatures().size();
        int feaCount2 = inGeoJson2.getFeatures().size();
        if(feaCount1==0 || feaCount2==0) {
            return "";
        }

        //2-GeoJson对象转换为Polygon 图形Wkt
        String geoType1 = inGeoJson1.getFeatures().get(0).getGeometry().getType();
        System.out.println();
        System.out.println("--->geoType1: "+ geoType1);
        System.out.println("--->1，读取GeoJson图形");

        List<StgeoFeature> stgeoFea1List = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson1);//被擦除的数据
        List<StgeoFeature> stgeoFea2List = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson2);//擦除范围

        System.out.println(String.format("--->被擦除的数据 size : %d ",stgeoFea1List.size()));
        //3-遍历被叠加的图层数据（批而未供），建立空间索引
        System.out.println();
        System.out.println("--->2，建立空间索引");
        Quadtree quadTree = new Quadtree();
        Iterator<StgeoFeature> stgeoIterator1 = stgeoFea1List.iterator();
        while (stgeoIterator1.hasNext()) {
            StgeoFeature stgeofea = stgeoIterator1.next();
            Geometry geom1 = (Geometry) stgeofea.getGeometry();
            Envelope itemEnv = geom1.getEnvelopeInternal();

            quadTree.insert(itemEnv, stgeofea);
        }

        System.out.println();
        System.out.println("--->3，相交判断");
        //通过初步判断，获取哪些图形被擦除数据inGeoJson1与擦除范围inGeoJson2相交
        Map<StgeoFeature,Set<StgeoFeature>> intersectSTGeoFeaSets = new HashMap<StgeoFeature,Set<StgeoFeature>>();
        for(int i=0; i<stgeoFea2List.size(); i++) {
            StgeoFeature stFea2 = stgeoFea2List.get(i);
            Geometry geom2 = stFea2.getGeometry();

            //通过空间索引，快速计算图形的包络线相交
            Set<StgeoFeature> intersectSTGeoFeaSet= new HashSet<StgeoFeature>();
            List<StgeoFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
            System.out.println(String.format("---quadTree->query, envelopeIntersections size: %d", envelopeIntersections.size()));
            int envelopeIntersectSize = envelopeIntersections.size();
            for(int j=0; j<envelopeIntersectSize; j++) {
                StgeoFeature stFea1 = envelopeIntersections.get(j);

                Geometry geom1 = stFea1.getGeometry();
                //StgeoFeature重载了hashCode代码。采用空间判断是否相交进行数据类
                if( geom1.intersects(geom2) ) {
                    intersectSTGeoFeaSet.add(stFea1);
                }
            }
            System.out.println(String.format("--->3.1 intersectSTGeoFeaSet size : %d ",intersectSTGeoFeaSet.size()));
            intersectSTGeoFeaSets.put(stFea2, intersectSTGeoFeaSet);
        }

        //获取未相交的部分
        Set<StgeoFeature> nullIntersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        //1.stgeoFea1
        for(int j=0; j<stgeoFea1List.size(); j++) {
            StgeoFeature stFea1 = stgeoFea1List.get(j);
            stFea1.setLayerFlag("1");
            for(Map.Entry<StgeoFeature, Set<StgeoFeature>> ent: intersectSTGeoFeaSets.entrySet() ) {
                Set<StgeoFeature> entVals = ent.getValue();
                if( !entVals.contains(stFea1) ) {
                    nullIntersectSTGeoFeaSet.add(stFea1);
                }
            }
        }
        //2.stgeoFea2
        for (int j = 0; j < stgeoFea2List.size(); j++) {
            StgeoFeature stFea2 = stgeoFea2List.get(j);
            stFea2.setLayerFlag("2");
            //很重要
            if (!intersectSTGeoFeaSets.containsKey(stFea2)) {
                nullIntersectSTGeoFeaSet.add(stFea2);
            }
        }
        System.out.println(String.format("--->3.2 nullIntersectSTGeoFeaSet size : %d ", nullIntersectSTGeoFeaSet.size()));


        System.out.println();
        System.out.println("--->4，构建字段结构SimpleFeatureType");
        StringBuilder sb = new StringBuilder();
        //字段类型集合
        Map<String,String> mapFieldTypes = new HashMap<String,String>();

        //构建FeatureTypeSchema
        String featureTypeSchema = "geometry:Polygon";
        Map<String,Object> props1 = stgeoFea1List.get(0).getProperties();
        Map<String,Object> props2 = stgeoFea2List.get(0).getProperties();
        if( bFirstAttributeSaved==true) {
            for(Map.Entry<String, Object> prop: props1.entrySet()) {
                String name = prop.getKey().toLowerCase();
                String subName = name.replace('.', '_');
                Object val = prop.getValue();

                String entType = "String";
                if(StringUtil.isNullOrEmpty(val)) {
                    entType = "String";
                }
                else if (StringUtil.isNumeric3(val.toString())) {
                    entType = "Double";
                }

                if( !"shape".equalsIgnoreCase(subName) && !"shape_area".equalsIgnoreCase(subName) &&  !"shape_leng".equalsIgnoreCase(subName)) {
                    if(!mapFieldTypes.containsKey(subName)) {
                        mapFieldTypes.put(subName, entType);
                    }
                }
            }
        }
        //图层2的字段新映射表
        Map<String,String> props2FieldMaps = new HashMap<String,String>();
        if( bSecondAttributeSaved==true) {
            for(Map.Entry<String, Object> prop: props2.entrySet()) {
                String name = prop.getKey().toLowerCase();
                String subName= name.replace('.', '_');
                Object val = prop.getValue();

                String fieldType = "String";
                if(StringUtil.isNullOrEmpty(val) ) {
                    fieldType = "String";;
                }

                if (StringUtil.isNumeric3(val.toString())) {
                    fieldType = "Double";
                }
                if( !"shape".equalsIgnoreCase(subName) && !"shape_area".equalsIgnoreCase(subName) &&  !"shape_leng".equalsIgnoreCase(subName)) {
                    //是否已存在该字段名
                    if(mapFieldTypes.containsKey(subName)) {
                        String newName = subName + "_1";

                        mapFieldTypes.put(newName, fieldType);
                        props2FieldMaps.put(subName, newName);
                    }else {
                        mapFieldTypes.put(subName, fieldType);
                        props2FieldMaps.put(subName, subName);
                    }
                }
            }
        }

        //根据mapFieldTypes构建字段TYPE
        System.out.println("mapfields: "+mapFieldTypes.toString());
        for(Map.Entry<String, String> fieldEnt: mapFieldTypes.entrySet()) {
            String fieldName = fieldEnt.getKey();
            String fieldType = fieldEnt.getValue();

            sb.append(String.format("%s:%s", fieldName, fieldType));
            sb.append(",");
        }
        // "String"、"Integer"、"Double"
        sb.append(String.format("%s:%s,", "shape_area", "Double"));
        sb.append(String.format("%s:%s,", "shape_leng", "Double"));
        sb.append(String.format("%s:%s", "union_flag", "String"));
        //sb.deleteCharAt(sb.length() - 1);
        featureTypeSchema = featureTypeSchema +","+ sb.toString();

        SimpleFeatureType TYPE =  DataUtilities.createType("Link", featureTypeSchema);
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        //1.第1部分---全部保留
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter writer = new WKTWriter();
        FeatureJSON fjson = new FeatureJSON();

        List<SimpleFeature> features = new ArrayList<>();
        SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
        System.out.println("--->5.1，全部保留");
        for(StgeoFeature stFea: nullIntersectSTGeoFeaSet) {
            Map<String,Object> properties = stFea.getProperties(); //属性集合
            Geometry geom = stFea.getGeometry(); //图形
            String unionFlag = stFea.getLayerFlag();//数据图层源信息
            System.out.println();

            String  geomType= geom.getGeometryType();
            String wkt = writer.write(geom);
            if("polygon".equalsIgnoreCase(geomType)) {
                //转换wkt为polygon
                Polygon polygon = (Polygon) reader.read(wkt);
                featureBuilder.add(polygon);
            }else if("multipolygon".equalsIgnoreCase(geomType)) {
                MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                for(Polygon p: polygons) {
                    featureBuilder.add(p);
                }
            }
            SimpleFeature feature = featureBuilder.buildFeature(null);

            //属性集合
            for(Map.Entry<String, Object>  prop : properties.entrySet()) {
                String fieldName = prop.getKey().toLowerCase();
                String subName = fieldName.replace('.', '_');//修正后的字段名
                String fieldType = mapFieldTypes.get(subName);//字段类型

                Object val = prop.getValue();
                String attrVal = "";
                if(val==null) {
                    attrVal="";
                }else {
                    attrVal=val.toString();
                }

                //String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");
                System.out.println(String.format("-->prop name: %s, val: %s", subName, attrVal));

                if( "shape".equalsIgnoreCase(subName)) {
                    continue;
                }else if("shape_area".equalsIgnoreCase(subName)) {
                    double shape_area = Double.parseDouble(attrVal);
                    feature.setAttribute(subName, shape_area);
                }
                else if("shape_leng".equalsIgnoreCase(subName)) {
                    double shape_length = Double.parseDouble(attrVal);
                    feature.setAttribute(subName, shape_length);
                }else {
                    if( mapFieldTypes.containsKey(subName) ) {
                        if("String".equalsIgnoreCase(fieldType)) {
                            feature.setAttribute(subName, attrVal);
                        }
                        else if("Double".equalsIgnoreCase(fieldType)){
                            double numAttrVal=0.0;
                            if(StringUtil.isNumeric3(attrVal)) {
                                numAttrVal = Double.parseDouble(attrVal);
                            }
                            feature.setAttribute(subName, numAttrVal);
                        }

                    }
                }
            }

            feature.setAttribute("union_flag", unionFlag);

            features.add(feature);
        }

        System.out.println("--->5.2，保留擦除后的那部分图形： 分为3种情况逐一出来");
        for(Map.Entry<StgeoFeature, Set<StgeoFeature>> ent: intersectSTGeoFeaSets.entrySet()) {
            StgeoFeature stFea2 = ent.getKey();
            Set<StgeoFeature> intersectSTGeoFeaSet1 = ent.getValue();
            //key geometry
            Geometry geom2 = stFea2.getGeometry();
            Map<String,Object> properties2 = stFea2.getProperties();
            //第2部分---保留擦除后的那部分图形
            //2.1 获取Geom1内，且Geom2以外非公共部分
            System.out.println("------>1.获取Geom1内且Geom2以外，非公共部分");
            for(StgeoFeature stFea1: intersectSTGeoFeaSet1) {
                Map<String,Object> properties1 = stFea1.getProperties(); //属性集合
                Geometry geom1 = stFea1.getGeometry();

                //很重要
                Geometry diffGeom = geom1.difference(geom2);//geom1擦除geom2后的剩余几何图形

                //类型、长度和面积
                String diffGeomType =diffGeom.getGeometryType();
                double area_diff = diffGeom.getArea();
                double length_diff = diffGeom.getLength();

                String wkt = writer.write(diffGeom);
                if("polygon".equalsIgnoreCase(diffGeomType)) {
                    //转换wkt为polygon
                    Polygon polygon = (Polygon) reader.read(wkt);
                    featureBuilder.add(polygon);
                }else if("multipolygon".equalsIgnoreCase(diffGeomType)) {
                    MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                    List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                    //featureBuilder.add(polygons.get(0));
                    for(Polygon p: polygons) {
                        featureBuilder.add(p);
                    }
                }

                SimpleFeature feature = featureBuilder.buildFeature(null);
                //属性集合
                for(Map.Entry<String, Object>  prop : properties1.entrySet()) {
                    String name = prop.getKey().toLowerCase();
                    String subName = name.replace('.', '_');
                    String fieldType = mapFieldTypes.get(subName);//字段类型

                    Object val = prop.getValue();
                    String attrVal = "";
                    if(val==null) {
                        attrVal="";
                    }else {
                        attrVal=val.toString();
                    }

                    if( "shape".equalsIgnoreCase(subName) ) {
                        continue;
                    }else if("shape_area".equalsIgnoreCase(subName)) {
                        double shape_area = Double.parseDouble(attrVal);
                        feature.setAttribute(subName, shape_area);
                    }else if("shape_leng".equalsIgnoreCase(subName)) {
                        double shape_length = Double.parseDouble(attrVal);
                        feature.setAttribute(subName, shape_length);
                    }else {
                        if(mapFieldTypes.containsKey(subName)) {
                            if("String".equalsIgnoreCase(fieldType)) {
                                feature.setAttribute(subName, attrVal);
                            }
                            else if("Double".equalsIgnoreCase(fieldType)){
                                double numAttrVal=0.0;
                                if(StringUtil.isNumeric3(attrVal)) {
                                    numAttrVal = Double.parseDouble(attrVal);
                                }
                                feature.setAttribute(subName, numAttrVal);
                            }
                        }else {
                            System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                        }
                    }
                }
                feature.setAttribute("shape_area", area_diff);
                feature.setAttribute("shape_leng", length_diff);
                feature.setAttribute("union_flag", "1");

                features.add(feature);
            }

            //2.2-获取与Geom2相交的公共部分
            System.out.println("------>2.获取Geom1内且Geom2相交后，共有部分");
            Set<Geometry> intersectGeoms = new HashSet<Geometry>();
            for(StgeoFeature stFea1: intersectSTGeoFeaSet1) {
                Map<String,Object> properties1 = stFea1.getProperties(); //属性集合
                Geometry geom1 = stFea1.getGeometry();

                //很重要
                Geometry intersectGeom = geom1.intersection(geom2);
                String intersectGeomType = intersectGeom.getGeometryType();
                if( intersectGeom != null && !intersectGeom.isEmpty()  ) {
                    double area_diff = intersectGeom.getArea();
                    double length_diff = intersectGeom.getLength();

                    String wkt = writer.write(intersectGeom);
                    if("polygon".equalsIgnoreCase(intersectGeomType)) {
                        //转换wkt为polygon
                        Polygon polygon = (Polygon) reader.read(wkt);
                        featureBuilder.add(polygon);
                    }else if("multipolygon".equalsIgnoreCase(intersectGeomType)) {
                        MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                        List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                        for(Polygon p: polygons) {
                            featureBuilder.add(p);
                        }
                    }

                    SimpleFeature feature = featureBuilder.buildFeature(null);
                    //属性1集合
                    for(Map.Entry<String, Object>  prop : properties1.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName= name.replace('.', '_');
                        String fieldType = mapFieldTypes.get(subName);//字段类型

                        Object val = prop.getValue();
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(subName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(subName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(subName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(subName)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(subName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(subName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(subName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(subName, numAttrVal);
                                }
                            }else {
                                System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                            }
                        }
                    }
                    //属性2集合
                    for(Map.Entry<String, Object>  prop : properties2.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName = name.replace('.', '_');


                        //与prop1重复字段 prop1_1
                        String newName = subName;
                        if(props2FieldMaps.containsKey(subName)) {
                            newName = props2FieldMaps.get(subName);
                        }
                        String fieldType = mapFieldTypes.get(newName);//字段类型

                        Object val = prop.getValue();//字段值
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(newName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(newName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(name)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(newName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(newName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(newName, numAttrVal);
                                }
                            }else {
                                System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                            }
                        }
                    }

                    feature.setAttribute("shape_area", area_diff);
                    feature.setAttribute("shape_leng", length_diff);
                    feature.setAttribute("union_flag", "12");

                    features.add(feature);

                    intersectGeoms.add(intersectGeom);
                }
            }

            //2.3-获取与geom2相交公共以外的部分，即剩余图形。geom2内，geom1外
            System.out.println("------>3.获取与geom2相交,公共以外的部分，即剩余图形");
            Geometry diffGeom = geom2;
            for(Geometry intersectGeom: intersectGeoms) {
                //迭代擦除所有相交部分图形
                diffGeom = diffGeom.difference(intersectGeom);
            }
            String symDiffGeoType = diffGeom.getGeometryType();
            if(diffGeom != null && !diffGeom.isEmpty() ) {
                double area_diff = diffGeom.getArea();
                double length_diff = diffGeom.getLength();

                String wkt = writer.write(diffGeom);
                if("polygon".equalsIgnoreCase(symDiffGeoType)) {
                    //转换wkt为polygon
                    Polygon polygon = (Polygon) reader.read(wkt);
                    featureBuilder.add(polygon);

                    SimpleFeature feature = featureBuilder.buildFeature(null);
                    //属性集合
                    for(Map.Entry<String, Object>  prop : properties2.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName= name.replace('.', '_');

                        //与prop1重复字段
                        String newName = subName;
                        if(props2FieldMaps.containsKey(subName)) {
                            newName = props2FieldMaps.get(subName);
                        }

                        String fieldType = mapFieldTypes.get(newName);//字段类型

                        Object val = prop.getValue();//字段值
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(newName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(newName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(newName)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(newName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(newName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(newName, numAttrVal);
                                }
                            }else {
                                System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                            }
                        }
                    }
                    feature.setAttribute("shape_area", area_diff);
                    feature.setAttribute("shape_leng", length_diff);
                    feature.setAttribute("union_flag", "2");

                    features.add(feature);
                }
                else if("multipolygon".equalsIgnoreCase(symDiffGeoType)) {
                    //转换wkt为polygon
                    MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                    List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                    for(int i=0; i<polygons.size(); i++)
                    {
                        Polygon polygon = polygons.get(i);
                        featureBuilder.add(polygon);

                        SimpleFeature feature = featureBuilder.buildFeature(null);
                        //属性集合
                        for(Map.Entry<String, Object>  prop : properties2.entrySet()) {
                            String name = prop.getKey().toLowerCase();
                            String subName = name.replace('.', '_');
                            //与prop1重复字段
                            String newName = subName;
                            if(props2FieldMaps.containsKey(subName)) {
                                newName = props2FieldMaps.get(subName);
                            }
                            String fieldType = mapFieldTypes.get(newName);//字段类型
                            Object val = prop.getValue();//字段值
                            String attrVal = "";
                            if(val==null) {
                                attrVal="";
                            }else {
                                attrVal=val.toString();
                            }


                            if( "shape".equalsIgnoreCase(newName) || "id".equalsIgnoreCase(newName)) {
                                continue;
                            }else if("shape_area".equalsIgnoreCase(newName)) {
                                double shape_area = Double.parseDouble(attrVal);
                                feature.setAttribute(newName, shape_area);
                            }else if("shape_leng".equalsIgnoreCase(newName)) {
                                double shape_length = Double.parseDouble(attrVal);
                                feature.setAttribute(newName, shape_length);
                            }else {
                                if(mapFieldTypes.containsKey(newName)){
                                    if("String".equalsIgnoreCase(fieldType)) {
                                        feature.setAttribute(newName, attrVal);
                                    }
                                    else if("Double".equalsIgnoreCase(fieldType)){
                                        double numAttrVal=0.0;
                                        if(StringUtil.isNumeric3(attrVal)) {
                                            numAttrVal = Double.parseDouble(attrVal);
                                        }
                                        feature.setAttribute(newName, numAttrVal);
                                    }
                                }else {
                                    System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                                }
                            }
                        }
                        feature.setAttribute("shape_area", area_diff);
                        feature.setAttribute("shape_leng", length_diff);
                        feature.setAttribute("union_flag", "2");

                        features.add(feature);
                    }
                }
            }
        }

        //转换为GeoJson
        System.out.println("--->6，将擦除后的图形转换为GeoJson");
        StringWriter strWriter = new StringWriter();
        fjson.writeFeatureCollection(collection, strWriter);
        String jsonStr = strWriter.toString();

        return jsonStr;
    }


    public static String spatialJoin(GeoJson inGeoJson1, GeoJson inGeoJson2 ) throws Exception {

        int feaCount1 = inGeoJson1.getFeatures().size();
        int feaCount2 = inGeoJson2.getFeatures().size();
        if(feaCount1==0 || feaCount2==0) {
            return "";
        }

        //2-GeoJson对象转换为Polygon 图形Wkt
        String geoType1 = inGeoJson1.getFeatures().get(0).getGeometry().getType();
        System.out.println();
        System.out.println("--->geoType1: "+ geoType1);
        System.out.println("--->1，读取GeoJson图形");

        List<StgeoFeature> stgeoFea1List = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson1);//被擦除的数据
        List<StgeoFeature> stgeoFea2List = JTSGeometryWKTUtil.geoJson2STGeoFeature(inGeoJson2);//擦除范围

        System.out.println(String.format("--->被擦除的数据 size : %d ",stgeoFea1List.size()));
        //3-遍历被叠加的图层数据（批而未供），建立空间索引
        System.out.println();
        System.out.println("--->2，建立空间索引");
        Quadtree quadTree = new Quadtree();
        Iterator<StgeoFeature> stgeoIterator1 = stgeoFea1List.iterator();
        while (stgeoIterator1.hasNext()) {
            StgeoFeature stgeofea = stgeoIterator1.next();
            Geometry geom1 = (Geometry) stgeofea.getGeometry();
            Envelope itemEnv = geom1.getEnvelopeInternal();

            quadTree.insert(itemEnv, stgeofea);
        }

        System.out.println();
        System.out.println("--->3，相交判断");
        //通过初步判断，获取哪些图形被擦除数据inGeoJson1与擦除范围inGeoJson2相交
        Map<StgeoFeature,Set<StgeoFeature>> intersectSTGeoFeaSets = new HashMap<StgeoFeature,Set<StgeoFeature>>();
        for(int i=0; i<stgeoFea2List.size(); i++) {
            StgeoFeature stFea2 = stgeoFea2List.get(i);
            Geometry geom2 = stFea2.getGeometry();

            //通过空间索引，快速计算图形的包络线相交
            Set<StgeoFeature> intersectSTGeoFeaSet= new HashSet<StgeoFeature>();
            List<StgeoFeature> envelopeIntersections = quadTree.query(geom2.getEnvelopeInternal());
            System.out.println(String.format("---quadTree->query, envelopeIntersections size: %d", envelopeIntersections.size()));
            int envelopeIntersectSize = envelopeIntersections.size();
            for(int j=0; j<envelopeIntersectSize; j++) {
                StgeoFeature stFea1 = envelopeIntersections.get(j);

                Geometry geom1 = stFea1.getGeometry();
                //StgeoFeature重载了hashCode代码。采用空间判断是否相交进行数据类
                if( geom1.intersects(geom2) ) {
                    intersectSTGeoFeaSet.add(stFea1);
                }
            }
            System.out.println(String.format("--->3.1 intersectSTGeoFeaSet size : %d ",intersectSTGeoFeaSet.size()));
            intersectSTGeoFeaSets.put(stFea2, intersectSTGeoFeaSet);
        }

        //获取未相交的部分
        Set<StgeoFeature> nullIntersectSTGeoFeaSet = new HashSet<StgeoFeature>();
        //1.stgeoFea1
        for(int j=0; j<stgeoFea1List.size(); j++) {
            StgeoFeature stFea1 = stgeoFea1List.get(j);
            stFea1.setLayerFlag("1");
            for(Map.Entry<StgeoFeature, Set<StgeoFeature>> ent: intersectSTGeoFeaSets.entrySet() ) {
                Set<StgeoFeature> entVals = ent.getValue();
                if( !entVals.contains(stFea1) ) {
                    nullIntersectSTGeoFeaSet.add(stFea1);
                }
            }
        }
        //2.stgeoFea2
        for (int j = 0; j < stgeoFea2List.size(); j++) {
            StgeoFeature stFea2 = stgeoFea2List.get(j);
            stFea2.setLayerFlag("2");
            //很重要
            if (!intersectSTGeoFeaSets.containsKey(stFea2)) {
                nullIntersectSTGeoFeaSet.add(stFea2);
            }
        }
        System.out.println(String.format("--->3.2 nullIntersectSTGeoFeaSet size : %d ", nullIntersectSTGeoFeaSet.size()));


        System.out.println();
        System.out.println("--->4，构建字段结构SimpleFeatureType");
        StringBuilder sb = new StringBuilder();
        //字段类型集合
        Map<String,String> mapFieldTypes = new HashMap<String,String>();

        //构建FeatureTypeSchema
        String featureTypeSchema = "geometry:Polygon";
        Map<String,Object> props1 = stgeoFea1List.get(0).getProperties();
        Map<String,Object> props2 = stgeoFea2List.get(0).getProperties();
        if( bFirstAttributeSaved==true) {
            for(Map.Entry<String, Object> prop: props1.entrySet()) {
                String name = prop.getKey().toLowerCase();
                String subName = name.replace('.', '_');
                Object val = prop.getValue();

                String entType = "String";
                if(StringUtil.isNullOrEmpty(val)) {
                    entType = "String";
                }
                else if (StringUtil.isNumeric3(val.toString())) {
                    entType = "Double";
                }

                if( !"shape".equalsIgnoreCase(subName) && !"shape_area".equalsIgnoreCase(subName) &&  !"shape_leng".equalsIgnoreCase(subName)) {
                    if(!mapFieldTypes.containsKey(subName)) {
                        mapFieldTypes.put(subName, entType);
                    }
                }
            }
        }
        //图层2的字段新映射表
        Map<String,String> props2FieldMaps = new HashMap<String,String>();
        if( bSecondAttributeSaved==true) {
            for(Map.Entry<String, Object> prop: props2.entrySet()) {
                String name = prop.getKey().toLowerCase();
                String subName= name.replace('.', '_');
                Object val = prop.getValue();

                String fieldType = "String";
                if(StringUtil.isNullOrEmpty(val) ) {
                    fieldType = "String";;
                }

                if (StringUtil.isNumeric3(val.toString())) {
                    fieldType = "Double";
                }
                if( !"shape".equalsIgnoreCase(subName) && !"shape_area".equalsIgnoreCase(subName) &&  !"shape_leng".equalsIgnoreCase(subName)) {
                    //是否已存在该字段名
                    if(mapFieldTypes.containsKey(subName)) {
                        String newName = subName + "_1";

                        mapFieldTypes.put(newName, fieldType);
                        props2FieldMaps.put(subName, newName);
                    }else {
                        mapFieldTypes.put(subName, fieldType);
                        props2FieldMaps.put(subName, subName);
                    }
                }
            }
        }

        //根据mapFieldTypes构建字段TYPE
        System.out.println("mapfields: "+mapFieldTypes.toString());
        for(Map.Entry<String, String> fieldEnt: mapFieldTypes.entrySet()) {
            String fieldName = fieldEnt.getKey();
            String fieldType = fieldEnt.getValue();

            sb.append(String.format("%s:%s", fieldName, fieldType));
            sb.append(",");
        }
        // "String"、"Integer"、"Double"
        sb.append(String.format("%s:%s,", "shape_area", "Double"));
        sb.append(String.format("%s:%s,", "shape_leng", "Double"));
        sb.append(String.format("%s:%s", "union_flag", "String"));
        //sb.deleteCharAt(sb.length() - 1);
        featureTypeSchema = featureTypeSchema +","+ sb.toString();

        SimpleFeatureType TYPE =  DataUtilities.createType("Link", featureTypeSchema);
        SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(TYPE);

        //1.第1部分---全部保留
        WKTReader reader = new WKTReader(geometryFactory);
        WKTWriter writer = new WKTWriter();
        FeatureJSON fjson = new FeatureJSON();

        List<SimpleFeature> features = new ArrayList<>();
        SimpleFeatureCollection collection = new ListFeatureCollection(TYPE, features);
        System.out.println("--->5.1，全部保留");
        for(StgeoFeature stFea: nullIntersectSTGeoFeaSet) {
            Map<String,Object> properties = stFea.getProperties(); //属性集合
            Geometry geom = stFea.getGeometry(); //图形
            String unionFlag = stFea.getLayerFlag();//数据图层源信息
            System.out.println();

            String  geomType= geom.getGeometryType();
            String wkt = writer.write(geom);
            if("polygon".equalsIgnoreCase(geomType)) {
                //转换wkt为polygon
                Polygon polygon = (Polygon) reader.read(wkt);
                featureBuilder.add(polygon);
            }else if("multipolygon".equalsIgnoreCase(geomType)) {
                MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                for(Polygon p: polygons) {
                    featureBuilder.add(p);
                }
            }
            SimpleFeature feature = featureBuilder.buildFeature(null);

            //属性集合
            for(Map.Entry<String, Object>  prop : properties.entrySet()) {
                String fieldName = prop.getKey().toLowerCase();
                String subName = fieldName.replace('.', '_');//修正后的字段名
                String fieldType = mapFieldTypes.get(subName);//字段类型

                Object val = prop.getValue();
                String attrVal = "";
                if(val==null) {
                    attrVal="";
                }else {
                    attrVal=val.toString();
                }

                //String attrVal = new String(val.toString().getBytes("UTF-8"), "GBK");
                System.out.println(String.format("-->prop name: %s, val: %s", subName, attrVal));

                if( "shape".equalsIgnoreCase(subName)) {
                    continue;
                }else if("shape_area".equalsIgnoreCase(subName)) {
                    double shape_area = Double.parseDouble(attrVal);
                    feature.setAttribute(subName, shape_area);
                }
                else if("shape_leng".equalsIgnoreCase(subName)) {
                    double shape_length = Double.parseDouble(attrVal);
                    feature.setAttribute(subName, shape_length);
                }else {
                    if( mapFieldTypes.containsKey(subName) ) {
                        if("String".equalsIgnoreCase(fieldType)) {
                            feature.setAttribute(subName, attrVal);
                        }
                        else if("Double".equalsIgnoreCase(fieldType)){
                            double numAttrVal=0.0;
                            if(StringUtil.isNumeric3(attrVal)) {
                                numAttrVal = Double.parseDouble(attrVal);
                            }
                            feature.setAttribute(subName, numAttrVal);
                        }

                    }
                }
            }

            feature.setAttribute("union_flag", unionFlag);

            features.add(feature);
        }

        System.out.println("--->5.2，保留擦除后的那部分图形： 分为3种情况逐一出来");
        for(Map.Entry<StgeoFeature, Set<StgeoFeature>> ent: intersectSTGeoFeaSets.entrySet()) {
            StgeoFeature stFea2 = ent.getKey();
            Set<StgeoFeature> intersectSTGeoFeaSet1 = ent.getValue();
            //key geometry
            Geometry geom2 = stFea2.getGeometry();
            Map<String,Object> properties2 = stFea2.getProperties();
            //第2部分---保留擦除后的那部分图形
            //2.1 获取Geom1内，且Geom2以外非公共部分
            System.out.println("------>1.获取Geom1内且Geom2以外，非公共部分");
            for(StgeoFeature stFea1: intersectSTGeoFeaSet1) {
                Map<String,Object> properties1 = stFea1.getProperties(); //属性集合
                Geometry geom1 = stFea1.getGeometry();

                //很重要
                Geometry diffGeom = geom1.difference(geom2);//geom1擦除geom2后的剩余几何图形

                //类型、长度和面积
                String diffGeomType =diffGeom.getGeometryType();
                double area_diff = diffGeom.getArea();
                double length_diff = diffGeom.getLength();

                String wkt = writer.write(diffGeom);
                if("polygon".equalsIgnoreCase(diffGeomType)) {
                    //转换wkt为polygon
                    Polygon polygon = (Polygon) reader.read(wkt);
                    featureBuilder.add(polygon);
                }else if("multipolygon".equalsIgnoreCase(diffGeomType)) {
                    MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                    List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                    //featureBuilder.add(polygons.get(0));
                    for(Polygon p: polygons) {
                        featureBuilder.add(p);
                    }
                }

                SimpleFeature feature = featureBuilder.buildFeature(null);
                //属性集合
                for(Map.Entry<String, Object>  prop : properties1.entrySet()) {
                    String name = prop.getKey().toLowerCase();
                    String subName = name.replace('.', '_');
                    String fieldType = mapFieldTypes.get(subName);//字段类型

                    Object val = prop.getValue();
                    String attrVal = "";
                    if(val==null) {
                        attrVal="";
                    }else {
                        attrVal=val.toString();
                    }

                    if( "shape".equalsIgnoreCase(subName) ) {
                        continue;
                    }else if("shape_area".equalsIgnoreCase(subName)) {
                        double shape_area = Double.parseDouble(attrVal);
                        feature.setAttribute(subName, shape_area);
                    }else if("shape_leng".equalsIgnoreCase(subName)) {
                        double shape_length = Double.parseDouble(attrVal);
                        feature.setAttribute(subName, shape_length);
                    }else {
                        if(mapFieldTypes.containsKey(subName)) {
                            if("String".equalsIgnoreCase(fieldType)) {
                                feature.setAttribute(subName, attrVal);
                            }
                            else if("Double".equalsIgnoreCase(fieldType)){
                                double numAttrVal=0.0;
                                if(StringUtil.isNumeric3(attrVal)) {
                                    numAttrVal = Double.parseDouble(attrVal);
                                }
                                feature.setAttribute(subName, numAttrVal);
                            }
                        }else {
                            System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                        }
                    }
                }
                feature.setAttribute("shape_area", area_diff);
                feature.setAttribute("shape_leng", length_diff);
                feature.setAttribute("union_flag", "1");

                features.add(feature);
            }

            //2.2-获取与Geom2相交的公共部分
            System.out.println("------>2.获取Geom1内且Geom2相交后，共有部分");
            Set<Geometry> intersectGeoms = new HashSet<Geometry>();
            for(StgeoFeature stFea1: intersectSTGeoFeaSet1) {
                Map<String,Object> properties1 = stFea1.getProperties(); //属性集合
                Geometry geom1 = stFea1.getGeometry();

                //很重要
                Geometry intersectGeom = geom1.intersection(geom2);
                String intersectGeomType = intersectGeom.getGeometryType();
                if( intersectGeom != null && !intersectGeom.isEmpty()  ) {
                    double area_diff = intersectGeom.getArea();
                    double length_diff = intersectGeom.getLength();

                    String wkt = writer.write(intersectGeom);
                    if("polygon".equalsIgnoreCase(intersectGeomType)) {
                        //转换wkt为polygon
                        Polygon polygon = (Polygon) reader.read(wkt);
                        featureBuilder.add(polygon);
                    }else if("multipolygon".equalsIgnoreCase(intersectGeomType)) {
                        MultiPolygon multipolygon = (MultiPolygon) reader.read(wkt);
                        List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multipolygon);
                        for(Polygon p: polygons) {
                            featureBuilder.add(p);
                        }
                    }

                    SimpleFeature feature = featureBuilder.buildFeature(null);
                    //属性1集合
                    for(Map.Entry<String, Object>  prop : properties1.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName= name.replace('.', '_');
                        String fieldType = mapFieldTypes.get(subName);//字段类型

                        Object val = prop.getValue();
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(subName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(subName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(subName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(subName)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(subName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(subName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(subName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(subName, numAttrVal);
                                }
                            }else {
                                System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                            }
                        }
                    }
                    //属性2集合
                    for(Map.Entry<String, Object>  prop : properties2.entrySet()) {
                        String name = prop.getKey().toLowerCase();
                        String subName = name.replace('.', '_');


                        //与prop1重复字段 prop1_1
                        String newName = subName;
                        if(props2FieldMaps.containsKey(subName)) {
                            newName = props2FieldMaps.get(subName);
                        }
                        String fieldType = mapFieldTypes.get(newName);//字段类型

                        Object val = prop.getValue();//字段值
                        String attrVal = "";
                        if(val==null) {
                            attrVal="";
                        }else {
                            attrVal=val.toString();
                        }

                        if( "shape".equalsIgnoreCase(newName) ) {
                            continue;
                        }else if("shape_area".equalsIgnoreCase(newName)) {
                            double shape_area = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_area);
                        }else if("shape_leng".equalsIgnoreCase(name)) {
                            double shape_length = Double.parseDouble(attrVal);
                            feature.setAttribute(newName, shape_length);
                        }else {
                            if(mapFieldTypes.containsKey(newName)){
                                if("String".equalsIgnoreCase(fieldType)) {
                                    feature.setAttribute(newName, attrVal);
                                }
                                else if("Double".equalsIgnoreCase(fieldType)){
                                    double numAttrVal=0.0;
                                    if(StringUtil.isNumeric3(attrVal)) {
                                        numAttrVal = Double.parseDouble(attrVal);
                                    }
                                    feature.setAttribute(newName, numAttrVal);
                                }
                            }else {
                                System.out.println(String.format("-->未找到字段信息: %s, %s",subName,fieldType));
                            }
                        }
                    }

                    feature.setAttribute("shape_area", area_diff);
                    feature.setAttribute("shape_leng", length_diff);
                    feature.setAttribute("union_flag", "12");

                    features.add(feature);

                    intersectGeoms.add(intersectGeom);
                }
            }
        }

        //转换为GeoJson
        System.out.println("--->6，将擦除后的图形转换为GeoJson");
        StringWriter strWriter = new StringWriter();
        fjson.writeFeatureCollection(collection, strWriter);
        String jsonStr = strWriter.toString();

        return jsonStr;
    }


    public static void main(String[] args) {
        String wktPoint = "POINT(103.83489981581 33.462715497945)";
        String wktLine = "LINESTRING(108.32803893589 41.306670233001,99.950999898452 25.84722546391)";
        String wktPolygon1 = "POLYGON((96.219409781775 32.777321394882,96.219409781775 40.240501628236,104.82491352023001 40.240501628236,104.82491352023001 32.777321394882,96.219409781775 32.777321394882))";
        String wktPolygon2 = "POLYGON((100.02715479879 32.168082192159,102.76873121104 37.194305614622,107.0334056301 34.909658604412,105.96723702534 30.949603786713,100.02715479879 32.168082192159))";

        String crs_wkt = "GEOGCS[\"China Geodetic Coordinate System 2000\"," + "    DATUM[\"China_2000\","
                + "        SPHEROID[\"CGCS2000\",6378137,298.257222101," + "            AUTHORITY[\"EPSG\",\"1024\"]],"
                + "        AUTHORITY[\"EPSG\",\"1043\"]]," + "    PRIMEM[\"Greenwich\",0,"
                + "        AUTHORITY[\"EPSG\",\"8901\"]]," + "    UNIT[\"degree\",0.0174532925199433,"
                + "        AUTHORITY[\"EPSG\",\"9122\"]]," + "    AUTHORITY[\"EPSG\",\"4490\"]]";

        // 创建工作目录
        String root = "D:\\temp\\stgeo\\shp";
        String dirName = "ss";
        File dirFolder = new File(root + File.separator + dirName);
        if (!dirFolder.exists()) {
            dirFolder.mkdirs();
        }

        JTSGeometryOperations geoOper = new JTSGeometryOperations();
        try {
            // geoOper.geoRelJudge();

            // String wkt = geoOper.geomOperIntersect(wktPolygon1, wktPolygon2);
            // String wkt = geoOper.geomOperUnion(wktPolygon1, wktPolygon2);
            // String wkt = geoOper.geomOperDifference(wktPolygon1, wktPolygon2);
            String wkt = JTSGeometryOperations.geomOperSymDifference(wktPolygon1, wktPolygon2);

            MultiPolygon multiPolygon = JTSGeometryWKTUtil.createMulPolygonByWKT(wkt);
            List<Polygon> polygons = JTSGeometryWKTUtil.multipolygon2Polygons(multiPolygon);
            // Polygon polygon = JTSGeometryWKTUtil.createPolygonByWKT(wkt);

            String filePath = root + File.separator + dirName + "\\" + "p1_symDiff_p2.shp";

            JTSGeometryWKTUtil.savePolygonsAsNewSHP(polygons, filePath);

        } catch (Exception e) {
            e.printStackTrace();
        }

        /*
         * String inputPath1 = "D:\\temp\\gtgis\\testtzdk2\\jsydgzq.shp";
         * String inputPath2 = "D:\\temp\\gtgis\\testtzdk2\\yjjbnt.shp";
          * String outputPath = "D:\\temp\\gtgis\\testtzdk2\\yjjbnt_jsydgzq.shp"; try {
         * geoOper.spatialIntersect(inputPath1, inputPath2, outputPath); } catch
         * (Exception e) { e.printStackTrace(); }
         */
    }
}
